home *** CD-ROM | disk | FTP | other *** search
- /*
- Attn: Programmers' Challenge Solution
- (progchallenge@xplain.com)
- MacTech Programmers Challenge - December 94
-
- SolveRubiksCube
- Copyright (c) 1994 J Robert Boonstra
- */
- /*
- * Problem Statement:
- *
- * Solve Rubiks cube, given an initial state by a call to
- * MikeCubeToRubiksCube. Provide access to solution
- * progress via RubiksCubeToMikeCube. Return 1 when cube
- * is solved, 0 after an intermediate move, and -1 if the
- * cube is unsolvable.
- *
- * Background
- *
- * Although it hasn't been proven, it is believed that
- * "God's algorithm" for solving the cube requires something
- * like 22 or 23 moves in the worst case. Back in the
- * 1970s, when the cube was introduced, Singmaster and
- * Thistlethwaite published solutions that solve the cube
- * in ~52 moves, and that result has probably been improved
- * upon since then. (These numbers may count half-turns
- * as a single move instead of two quarter-turn moves -
- * some people prefer to count that way.) For those
- * interested in the cube, there is an active mailing list -
- * send mail to cube-lovers-request@ai.mit.edu for more
- * info. In the event that Singmaster, Thistlethwaite, God,
- * or an avid cube-lover don't enter the challenge, we
- * offer this solution.
- *
- * Solution strategy
- *
- * This solution is based on the now out-of-print book
- * by Don Taylor, entitled "Mastering Rubik's Cube", and
- * sold at the time for the princely sum of $1.95. While
- * not in any way optimal, the solution in the book has
- * the advantage of being (relatively) easy to remember.
- *
- * We solve the cube using the following steps:
- *
- * 1. Solve the edge cubes in the top layer.
- * 2. Solve the corner cubes in the top layer.
- * 3. Solve the (edge) cubes in the middle layer.
- * 4. Move the corner cubes in the bottom layer to the
- * correct position.
- * 5. Orient the bottom layer corner cubes correctly.
- * 6. Move the edge cubes in the bottom layer to the
- * correct position.
- * 7. Orient the bottom layer edge cubes correctly.
- *
- * This solution trades a large amount of space (code) for
- * speed. The operators that transform the cube are coded
- * as macros, rather than as subroutines. (These macros
- * were generated by an auxiliary program.)
- */
-
- #pragma options(honor_register,assign_registers)
-
- #include "rubik.h"
- #include "transform.h"
-
- char *theMoveP; /* pointer to stored moves */
- char *lastMoveP; /* pointer to final move */
- short firstTime; /* set to 1 by MikeCubeToRubiksCube */
-
- int SolveRubiksCube(register RubiksCube *rub)
- {
- register unsigned short ch;
- if (firstTime) {
- /*
- * First time through, check to see if the cube is legal.
- * Check for existence of the required corners/edges.
- * (We also could check the twist on the corners and the
- * flip parity on the edges to ensure that the cube is
- * solvable, but I never got that working.)
- */
- if (!LegalCube(rub)) return(-1);
- /*
- * Find complete solution on first call. Play back on
- * subsequent calls.
- *
- * Initial solution split into subroutine calls to
- * deal with Symantec C limit on code in one file.
- */
- SolveTopEdgesFR(rub);
- SolveTopEdgesLB(rub);
- if (!SolveTopCorners(rub)) return (-1);
- if (!SolveMiddleLayer(rub)) return (-1);
- if (!SolveBottomCorners(rub)) return (-1);
- if (!SolveBottomEdges(rub)) return (-1);
- firstTime = 0;
- /*
- * Restore the initial cube state so that we can play back
- * the moves one at a time.
- */
- lastMoveP = theMoveP;
- theMoveP = rub->theMove;
- {
- register long *p=(long *)&rub->cubie[0][0];
- register ct=16*8/sizeof(long);
- do {
- *p = *(p+ 16*8/sizeof(long));
- ++p;
- } while (--ct);
- }
- }
- ch = *theMoveP;
- switch (ch) {
- case U: U1move; break;
- case F: F1move; break;
- case L: L1move; break;
- case D: D1move; break;
- case B: B1move; break;
- case R: R1move; break;
- case u: U3move; break;
- case f: F3move; break;
- case l: L3move; break;
- case d: D3move; break;
- case b: B3move; break;
- case r: R3move; break;
- }
- return (lastMoveP == ++theMoveP);
- }
-
- #define CornerVal(X,Y,Z) \
- ((1<<(X##Y##Z##_##X)) | (1<<X##Y##Z##_##Y) | \
- (1<<X##Y##Z##_##Z))
-
- #define EdgeVal(X,Z) \
- ((1<<(X##Z##_##X)) | (1<<X##Z##_##Z))
-
- #define crn(a,b,c) ((1<<a) | (1<<b) | (1<<c))
- #define edg(a,b) ((1<<a) | (1<<b))
-
- static Boolean LegalCube(RubiksCube *rub)
- {
- char cubeValues[20];
- register long whichCubes=0;
- register char *valP;
- register short count,theVal;
-
- /*
- * Make certain all the necessary corner cubes are there.
- */
- valP = cubeValues;
- *valP++ = CornerVal(U,L,F);
- *valP++ = CornerVal(U,R,F);
- *valP++ = CornerVal(U,L,B);
- *valP++ = CornerVal(U,R,B);
- *valP++ = CornerVal(D,L,F);
- *valP++ = CornerVal(D,R,F);
- *valP++ = CornerVal(D,L,B);
- *valP++ = CornerVal(D,R,B);
-
- valP = cubeValues;
- count=8;
- whichCubes=0;
- do {
- theVal = *valP++;
- if (theVal == crn(U,L,F)) {whichCubes|=0x01; continue;}
- if (theVal == crn(U,R,F)) {whichCubes|=0x02; continue;}
- if (theVal == crn(U,L,B)) {whichCubes|=0x04; continue;}
- if (theVal == crn(U,R,B)) {whichCubes|=0x08; continue;}
- if (theVal == crn(D,L,F)) {whichCubes|=0x10; continue;}
- if (theVal == crn(D,R,F)) {whichCubes|=0x20; continue;}
- if (theVal == crn(D,L,B)) {whichCubes|=0x40; continue;}
- if (theVal == crn(D,R,B)) {whichCubes|=0x80; continue;}
- return false;
- } while (--count);
- if (whichCubes != 0xFF) return false;
-
- /*
- * Make certain all the necessary edge cubes are there.
- */
- valP = cubeValues+8;
- *valP++ = EdgeVal(U,L); *valP++ = EdgeVal(U,R);
- *valP++ = EdgeVal(D,L); *valP++ = EdgeVal(D,R);
- *valP++ = EdgeVal(U,F); *valP++ = EdgeVal(U,B);
- *valP++ = EdgeVal(D,F); *valP++ = EdgeVal(D,B);
- *valP++ = EdgeVal(L,F); *valP++ = EdgeVal(L,B);
- *valP++ = EdgeVal(R,F); *valP++ = EdgeVal(R,B);
-
- valP = cubeValues+8;
- count=12;
- whichCubes=0;
- do {
- theVal = *valP++;
- if (theVal == edg(U,L)) {whichCubes|=0x0001; continue;}
- if (theVal == edg(U,R)) {whichCubes|=0x0002; continue;}
- if (theVal == edg(D,L)) {whichCubes|=0x0004; continue;}
- if (theVal == edg(D,R)) {whichCubes|=0x0008; continue;}
- if (theVal == edg(U,F)) {whichCubes|=0x0010; continue;}
- if (theVal == edg(U,B)) {whichCubes|=0x0020; continue;}
- if (theVal == edg(D,F)) {whichCubes|=0x0040; continue;}
- if (theVal == edg(D,B)) {whichCubes|=0x0080; continue;}
- if (theVal == edg(L,F)) {whichCubes|=0x0100; continue;}
- if (theVal == edg(L,B)) {whichCubes|=0x0200; continue;}
- if (theVal == edg(R,F)) {whichCubes|=0x0400; continue;}
- if (theVal == edg(R,B)) {whichCubes|=0x0800; continue;}
- return false;
- } while (--count);
- if (whichCubes != 0xFFF) return false;
-
- return (true);
- }
-